標籤:API 設計
公開介面與已發佈介面
許多現代語言在模組中區分公開和私有功能。公開和已發佈功能之間的區分並不常見:這可能是一個更重要的區分。
重構模組相依性
隨著程式碼的規模越來越大,將其分割成模組非常重要,如此一來,您不需了解所有程式碼即可進行小幅修改。這些模組通常可以由不同的團隊提供,並動態地結合在一起。在這篇重構文章中,我使用簡報-網域-資料分層分割了一個小型程式碼。然後,我重構這些模組之間的相依性,以引入服務定位器和相依性注入模式。這些模式適用於不同的語言,但看起來不同,因此我在 Java 和無類別 JavaScript 樣式中展示這些重構。
集合管線
集合管線是一種程式設計模式,您將一些運算組織成一系列作業,這些作業透過將集合作為一個作業的輸出,並將其提供給下一個作業來組合。(常見的作業有篩選、對應和還原。)這種模式在函數式程式設計中很常見,在具有 lambda 的物件導向語言中也很常見。本文描述了此模式,並提供了幾個如何形成管線的範例,既可以向不熟悉此模式的人介紹此模式,也可以幫助人們了解核心概念,以便他們可以更輕鬆地將想法從一種語言轉換到另一種語言。
微服務與分散式物件的第一法則
在 EAA 的 P 中,我說「不要分散你的物件」。這項建議是否與我對微服務的興趣相矛盾?
API 不應具有著作權
API 不應具有著作權,以便程式設計人員可以重新實作介面來支援測試、互通性,並鼓勵競爭。
雙時態歷史
通常需要存取某些屬性的歷史值。但有時此歷史記錄本身需要根據追溯更新進行修改。雙時態歷史將時間視為兩個面向:實際歷史記錄應如何給予完美的資訊傳輸,而記錄歷史則記錄我們對歷史的認知如何改變。
CQRS
CQRS 代表命令查詢責任隔離。這是由 Greg Young 最早描述的模式。其核心概念是,你可以使用不同的模型來更新資訊,而不是使用你用來讀取資訊的模型。在某些情況下,這種分離可能很有價值,但請注意,對於大多數系統而言,CQRS 會增加風險複雜性。
命令導向介面
模組最常見的介面樣式是使用程序或物件方法。因此,如果你希望模組計算合約的一堆費用,你可能會有一個 BillingService 類別,其中有一個方法可以進行計算,像這樣呼叫它
aBillingService.calculateCharges(aContract)
以指令為導向的介面會為每個操作提供一個指令類別,並以類似方式呼叫
CalculateChargeCommand.new(aContract).run()
指令查詢分離
「指令查詢分離」一詞是由 Bertrand Meyer 在其著作「物件導向軟體建構」中所創造的,這本書是 OO 早期最具影響力的 OO 書籍之一。(第一版具有影響力,第二版很好,但您需要在健身房待上幾個月才能舉起它。)
建構函式初始化
建構函式初始化是一種方法,您可以在物件的建立方法中傳入物件所需的所有合作者。它是 SetterInitialization 的替代方案。
禮貌實作
當您撰寫類別時,您大多會努力確保該類別的功能對該類別有意義。但有時,新增一個功能以允許類別符合它自然應該具備的更豐富介面是有意義的。
裝飾指令
這是一個非常常見且非常簡單的模式,它實際上只是套用在指令上的裝飾模式。我看到它經常與 CommandOrientedInterface 一起使用。您也會聽到這稱為攔截器,以及面向方面程式設計的一種形式。
設計繼承
物件導向圈中最長久的論點之一是 開放繼承 和設計繼承之間的爭論。設計繼承的原則可能由 Josh Bloch 最好地總結:「設計和文件化繼承,否則禁止它」。透過這種方法,您可以仔細決定哪些方法可以繼承,並 封裝 其他方法以阻止它們被覆寫。
鴨子介面
也許我太天真了,但我從未預期過我在 HumaneInterface 上發布的文章會引發如此熱烈的討論。遺憾的是,大部分的討論都變成 Ruby 的陣列和 Java 的清單的優缺點,而不是我試圖提出的基本觀點,但儘管如此,我認為一些不錯的對話支流已經出現。
其中一個對話串指出,陣列和清單之間的差異除了人道/極簡哲學之外,還有其他原因。其中一個原因與類似功能在兩種語言中扮演不同角色的方式有關。
標記參數
標記參數是一種函數參數,它會告訴函數根據其值執行不同的運算。想像一下我們想要預訂一場音樂會。有兩種方式可以做到這一點:一般和高級。要在此處使用標記參數,我們會得到以下方法宣告
流暢介面
幾個月前,我參加了 Eric Evans 的研討會,他談到了一種特定的介面樣式,我們決定將其命名為流暢介面。這不是一種常見的樣式,但我們認為應該更廣為人知。描述它的最佳方式可能是舉例說明。
基礎平台
基礎平台是在其上建置任何應用程式之前建置的。這個想法是分析需要平台的各種應用程式的需求,然後建置平台。一旦平台完成,您就可以在其上建置應用程式。重點是平台在您開始處理應用程式之前真的需要有一個穩定的 API,否則由於平台對應用程式的連鎖效應,平台的變更將難以管理。
Getter Eradicator
當他們看到 getter 方法時,你可以從他們嘴巴左邊的抽搐看出,他們迅速地拉動他們的戰斧,並發出滿足的叫聲,因為另一個 getter 從一個立即在感激的 Getter Eradicator 的腳下昏厥的類中毫不留情地被砍掉。
收割平台
要透過收割來建立平台,你首先不要嘗試建立平台,而是建立一個應用程式。在建立應用程式的同時,你不會嘗試開發通用程式碼,但你確實努力建立一個結構良好且設計良好的應用程式。
標頭介面
標頭介面是一個明確的介面,模擬類別的隱含公開介面。基本上,你採用類別的所有公開方法,並在介面中宣告它們。然後,你可以為類別提供替代實作。這與 RoleInterface 相反 - 我在那裡討論更多詳細資訊和優缺點。
人道介面
在 ruby 社群待了一段時間後,我常常遇到「人道介面」這個術語。它描述了 rubyist 對撰寫類別介面的態度的一部分,我認為它也建立了 API 設計中兩個思想流派之間的有趣對比(另一個是 MinimalInterface)。
隱含介面實作
Java 和 C# 都共用純介面類型的相同模型。你可以透過轉到 interface Mailable
來宣告一個純介面,然後你可以宣告你使用 class Customer implements Mailable
(在 Java 中)來實作它。一個類別可以實作任意數量的純介面。這個模型忽略的事情之一是,每當你有一個類別時,你就會有隱含介面。
介面實作配對
將每個類別與介面配對的做法。因此,你會看到成對的事物 - 也許是 ICustomer 和 Customer 或 Customer 和 CustomerImpl。在許多方面,它呼應了 C/C++ 為每個類別建立標頭檔案的習慣,儘管在這種情況下,介面和實作實際上是不同的類型。
控制反轉
控制反轉是你擴充架構時會遇到的常見現象。事實上,它通常被視為架構的定義特徵。
最小介面
極簡介面是一種 API 設計風格,我將它與 HumaneInterface 做對比。極簡介面的概念是設計一個 API,讓客戶端可以執行他們需要執行的所有操作,但將功能簡化為最小的合理方法集,以完成工作。(請參閱 HumaneInterface,了解兩者差異的良好範例。)
開放繼承
這與 DesignedInheritance 的態度相反。開放繼承的倡導者不會透過 Seal 封裝類別或採取其他措施來阻止人們繼承類別,以禁止繼承。
重載的 Getter Setter
我最近一直在研究 JavaScript,其中一件事讓我印象深刻的是,使用相同函數名稱作為 getter 和 setter 的習慣。因此,如果您想在 jQuery 中找出橫幅的高度,您會使用 $("#banner").height()
,而如果您想變更高度,您會使用 $("#banner").height(100)
。
這個慣例對我來說很熟悉,因為 Smalltalk 使用過它。您可以使用 banner height
取得值,並使用 banner height: 100
變更值。知道它是 Smalltalk 慣例就足以讓我喜歡它,因為我對那門語言有一種遙遠但持久的愛。但即使是最好的事物也有缺點,我無法隱藏我對這種編碼風格的不喜歡。
平行變更
對介面進行影響所有使用者的變更,需要兩種思考模式:實作變更本身,然後更新所有用法。當您嘗試同時執行這兩項操作時,這可能會很困難,特別是如果變更在具有多個或外部客戶端的 PublishedInterface 上。
平行變更,也稱為擴充和收縮,是一種模式,可以安全地對介面實作後向不相容的變更,方法是將變更分成三個不同的階段:擴充、遷移和收縮。
已發佈介面
已發布介面是我使用的術語(首次出現在Refactoring中),用來指在定義它的程式碼庫外部使用的類別介面。因此,它的意義比 Java 中的 public 更廣泛,甚至比 C# 中的非內部 public 更廣泛。我在 IEEE Software 的專欄中論證已發布和 public 之間的區別實際上比 public 和 private 之間的區別更重要。
所需介面
所需介面是由互動的客戶端定義的介面,它指定供應元件需要執行的動作,以便在該互動中使用它。
角色介面
角色介面是透過檢視供應商和消費者之間的特定互動來定義的。供應元件通常會實作多個角色介面,每個介面對應於這些互動模式之一。這與HeaderInterface形成對比,在後者中,供應商只會有一個介面。
規則引擎
我應該使用規則引擎嗎?
封裝
封裝方法或類別可以防止子類別覆寫它。
設定值初始化
使用設定值初始化,您可以建構一個空物件,然後使用設定值方法在過程中設定各種屬性。(ConstructorInitialization的替代方案。)
告訴,別詢問
告訴,別詢問是一個原則,它幫助人們記住物件導向是關於將資料與對該資料進行運算的函式綑綁在一起。它提醒我們,與其詢問物件資料並對該資料進行操作,我們應該告訴物件該做什麼。這鼓勵將行為移到物件中,以配合資料。
兩件難事
在電腦科學中只有兩件難事:快取失效和命名事物。
-- Phil Karlton
型別化集合
當人們開始使用物件時,特別是在強型別語言中,一個常見的問題是他們是否應該為不同的網域型別擁有特定的集合類別。因此,如果您有一個儲存員工集合的公司類別,您應該使用程式庫中的常規集合類別,還是應該建立一個特定的 EmployeeList
類別 - 一個型別化集合。
統一存取原則
模組提供的全部服務都應該透過統一符號提供,不會洩露它們是透過儲存或運算來實作。
-- Bertrand Meyer
Bertrand Meyer 在他極具影響力的著作 物件導向軟體建構 中創造了這個原則。
這個原則的重點是,如果您有一個人物物件,並且詢問它的年齡,您應該使用相同的符號,無論年齡是物件的儲存欄位或計算值。這實際上表示人物的客戶既不應該知道也不應該關心年齡是儲存還是計算出來的。
使用者定義欄位
軟體系統中的一個常見功能是允許使用者在資料結構中定義自己的欄位。考慮一個通訊錄 - 有許多您可能想要新增的東西。隨著每天都有新的社群網路出現,使用者可能想要為他們的聯絡人新增一個 Bunglr ID 的新欄位。
值物件
在編寫程式時,我常發現將事物表示為複合體很有用。2D 座標包含 x 值和 y 值。一筆金額包含數字和貨幣。日期範圍包含開始日期和結束日期,而它們本身可以是年、月和日的複合體。
在這樣做的過程中,我遇到了兩個複合物件是否相同的疑問。如果我有兩個點物件,它們都表示 (2,3) 的笛卡兒座標,那麼將它們視為相等是有道理的。由於其屬性的值(在本例中為其 x 和 y 座標)而相等的物件稱為值物件。